# GNAFU - "Ground, Navy and Air Fuck-Up" real-time strategy game
# Copyright (C) 2008-2009 k0wax <k0waxk0wax@gmail.com>
#
# This file is part of GNAFU.
#
# GNAFU is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNAFU is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNAFU.  If not, see <http://www.gnu.org/licenses/>.

"""Custom pickling"""
from __future__ import division, absolute_import
import pickle, shelve, copy, gc
import copy_reg as copyreg
from cStringIO import StringIO
from src import entity

"""Patched pickle that automatically drop _view_dict items
from object's __dict__
"""
_saved_table = pickle.dispatch_table.copy()
def _safe_pickle(f, *args):
    """pickle.dispatch_table sandboxing

    Restore pickle.dispatch_table to saved default.
    Used for prevent infinite loops."""
    print 'safe pickling obj', type(args[0])
    tmp = pickle.dispatch_table.copy()
    #pickle.dispatch_table = _saved_table
    del pickle.dispatch_table[type(args[0])]
    print 'DISPATCH_TABLE', pickle.dispatch_table
    data = f(*args)
    pickle.dispatch_table.update(tmp)
    #print 'return data', data
    print 'return disp tbl', pickle.dispatch_table
    return data

def shit_unpickler(data):
    #print 'shit unpickler'
    return pickle.loads(data)

def drop_view_dict(obj):
    """Drops _view_dict items from obj.__dict__ and _view_dict itself"""
    if hasattr(obj, '_view_dict') and type(obj) != type(type): # reduce obj
        print '\n--> removing _view_dict items from %s __dict__ id: %d\n' \
            % (type(obj), id(obj))
        saved_view_dict = {}
        for k in obj._view_dict.keys():
            # refill saved_view_dict with actual values of object's dict
            # cannot use values from _view_dict
            saved_view_dict[k] = obj.__dict__[k]
        print 'obj _view_dict'
        print obj._view_dict
        print 'obj dict'
        print obj.__dict__
        print 'obj type:', type(obj)
        for k, v in obj._view_dict.items():
            if k == '_view_dict':
                continue
            try:
                del obj.__dict__[k]
                print ' -> dropped', k
            except:
                print 'FAIL. cannot drop', k, 'from __dict__' 
                print 'content of saveobj.__dict__ is:'
                print obj.__dict__
        del obj._view_dict
        print '--->'
        print 'PICKLING OBJ', type(obj), obj, obj.__dict__
        data = _safe_pickle(pickle.dumps, obj)
        print 'PICKLING OK'
        # .. restore obj's state
        print 'a->', obj.__dict__
        print obj.draw
        obj._view_dict = saved_view_dict.copy()
        obj.__dict__.update(obj._view_dict)
        print 'b->', obj.__dict__
        print obj.draw
    else:
        print obj
        return
    return shit_unpickler, (data, )

def wrap_save(f):
    def wrapper(*args, **kw):
        obj = args[1]
        if hasattr(obj, '_view_dict') and type(obj) != type(type): # reduce obj
            print '** save wrap', type(obj)
            copyreg.pickle(type(obj), drop_view_dict, shit_unpickler)
            global _saved_table
            _saved_table = pickle.dispatch_table.copy()
            print '** installed hook for ', type(obj), obj
            print 'disp tbl', pickle.dispatch_table
            #import pdb; pdb.set_trace()
        return f(*args, **kw)
    return wrapper

Pickler = pickle.Pickler
Pickler.save = wrap_save(Pickler.save)

def dumps(obj):
    pickle.Pickler = Pickler
    return pickle.dumps(obj)

def loads(obj):
    pickle.Pickler = Pickler
    return pickle.loads(obj)

